<% ASP на блюдечке %>. Часть 14

Разработка системы электронного голосования

Рубен Садоян

Введение

Электронное голосование — что это такое?

Электронное голосование — а зачем оно?

Что нам понадобится?

Создание и подготовка базы данных

Интеграция системы в уже готовый сайт

Главная страничка (файл Vindex.asp)

Заключение

Введение

Рассмотренные нами в предыдущих частях настоящей статьи примеры в той или иной степени представляли собой разнообразные интерфейсы к базам данных. А такая задача как разработка системы электронного голосования, нами пока не рассматривалась. В настоящей статье представлен материал, который позволит самостоятельно разработать такую систему, а также рассмотрен вопрос об организации переносимых модулей, позволяющих обеспечить легкое и удобное встраивание такой системы практически в любой сайт независимо от его сложности.

В начало В начало

Электронное голосование — что это такое?

Разумеется, речь идет о наиболее типичной системе электронного голосования. Прежде всего — это система, предлагающая пользователю вопрос и несколько наиболее типичных вариантов ответа на него. Кроме того, это система сбора данных (обработки пользовательского ввода) и выдачи интегральных результатов голосования как в численном, так и в графическом представлении.

Сама система выбора того или иного варианта ответа может быть представлена как посредством логики «или», так и логики «и». Другими словами, в зависимости от того, допустим выбор более чем одного варианта ответа на поставленный вопрос или нет, может применяться одна из двух схем анализа ответа и соответственно один из двух компонентов формы опроса («радиокнопки» или «чекбоксы»). Но об этом чуть позже, а для начала все-таки уясним, какую выгоду может дать организация системы электронного голосования на вашем сайте.

В начало В начало

Электронное голосование — а зачем оно?

Этот тривиальный вопрос может возникнуть у многих читателей. Во-первых, система электронного голосования может пробудить интерес к вашему сайту (например, пользователи вашего сайта могут пригласить поучаствовать в голосовании своих знакомых или коллег). Здесь наиболее существенным является постановка самой задачи голосования. Нередки случаи, когда вопрос выбирается с таким расчетом, чтобы втянуть отвечающих на него в дискуссию на форуме или в чате на том же сайте. Это делается специально для повышения активности сайта. Представьте себе, что вопрос звучит, к примеру так: «Сотовым телефоном какого производителя вы пользуетесь?» или «Доверяете ли вы президенту?». Таким образом, правильная постановка и выбор самого вопроса является мощным инструментом привлечения внимания к тому или иному сайту и в удачном сочетании с другим функционалом может обеспечить реальный успех в его продвижении.

В начало В начало

Что нам понадобится?

Разумеется, предполагается, что читатель знаком с основами ASP- и SQL-программирования (первых частей настоящей статьи для этого будет вполне достаточно). Кроме того, нам потребуется Microsoft SQL Server 7.0 или 2000, какой-нибудь HTML- или текстовый редактор (рекомендую использовать Macromedia Dreamweaver UltraDev 4.0) и немного терпения.

В начало В начало

Создание и подготовка базы данных

Создадим две таблицы: таблицу вопросов (VQuestions) и таблицу ответов (VAnswers). В таблице ответов заведем поле (Total) для регистрации количества полученных ответов. Представим себе их взаимосвязь так, как показано на рисунке.

Ключевыми здесь являются столбцы ID. A взаимосвязь столбца QuestionID таблицы ответов с столбцом ID таблицы вопросов, по сути, отражает взаимосвязь вопросов и ответов.

Далее необходимо прописать нашу базу данных в соответствующем разделе источников данных системы. Для этого сделайте следующее:

          Voter          SQL Server

Теперь, когда база данных готова, можно переходить к созданию самой системы электронного голосования.

Однако сначала необходимо уяснить еще один вопрос. Каким именно образом будет выбираться тот или иной вопрос из базы данных, ведь в общем случае (а мы рассмотрим именно его) вопросов в базе может быть несколько.

Для этого мы будем каждый раз выбирать тот или иной вопрос из базы данных случайным образом (с помощью генератора случайных значений).

В начало В начало

Интеграция системы в уже готовый сайт

Дело в том, что само по себе голосование не имеет смысла. Посудите сами, кому нужен сайт, предназначенный исключительно для системы электронного голосования. С другой стороны, интеграция его в уже готовый сайт «в чистом виде» может создать сложности — как для восприятия исходного текста, так и в дальнейшем, например, если потребуется временно отключить голосование. Поэтому попытаемся разработать систему таким образом, чтобы ее интеграция в уже готовый сайт не составила труда. Для этого необходимо сформировать независимый модуль системы и «включить» его в текст основного сайта там, где это необходимо. Так, к примеру, текст страницы вашего сайта может выглядеть следующим образом:

<head>  
<title>ASP на блюдечке (Часть - 14) - Разработка системы электронного голосования</title>  
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">  
</head>  
   
<body  marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" >  
…  
<!-- #include file="Vindex.asp"-->  
…  
</body>  
</html>  

или

<!-- #include file="mainheader.inc"-->  
<!-- #include file="Vindex.asp"-->  
<!-- #include file="mainfooter.inc"-->  

Как видите, в первом случае директива о включении странички с системой голосования (<!-- #include file="Vindex.asp"-->) указана в необходимом месте. Во втором случае страничка исходного сайта представлена в виде трех последовательно «включаемых» элементов: начала, странички с голосованием и конца. Использование того или иного способа организации структуры странички вашего сайта — дело вкуса и зависит от структуры исходного сайта, а также от степени его сложности.

В начало В начало

Главная страничка (файл Vindex.asp)

Прежде всего необходимо разработать страничку, осуществляющую показ вопроса и вариантов ответов на него (здесь и далее мы будем использовать логическую схему «или» для получения ответа пользователей).  Для этого сначала напишем пару функций для осуществления соединения с базой данных и отключения от нее:

<%  
 Sub Connect()  
  dsn = "DSN=Voter; UID=sa;PWD=;database=Voter"  
  Set conn = Server.createobject("adodb.connection")  
  Set rs = Server.createobject("adodb.recordset")  
  conn.open dsn  
 End Sub  
   
 Sub Close()  
  rs.close  
  set rs=nothing  
  conn.close  
  set conn=nothing  
 End Sub  
%>  

    Далее нам потребуется функция извлечения ответов на данный вопрос. Она будет служить для выборки соответствующих ответов с последующим формированием элементов интерфейса пользовательской формы на их основе:

<%  
 Sub FindAns(QID)  
  call connect()  
  sql="SELECT id, ansdesc FROM VAnswers WHERE QuestionID = " & QID & " ORDER BY id"  
  rs.open sql,conn  
 End Sub  
%>  

   Теперь установим опции «предзагрузки» пяти изображений, соответствующих пяти возможным вариантам ответов пользователей, которые будут служить для графической интерпретации ответов пользователей (изображения подготовим заранее).

<html>  
<head>  
<script>  
 img1 = new Image();   
 img1.src = "images/Voter/char1.gif";     
   
 img2 = new Image();   
 img2.src ="images/Voter/char2.gif";     
   
 img3 = new Image();   
 img3.src = "images/Voter/char3.gif";     
   
 img4 = new Image();   
 img4.src = "images/Voter/char4.gif";     
   
 img5 = new Image();   
 img5.src = "images/Voter/char5.gif";     
…  

 Определим функцию, которая будет перемещать пользователя на страничку просмотра результатов голосования, причем передадим ей в качестве параметра action значение view:

…  
 function gotoResults()  
 {  
  location.href="Voter.asp?action=view"  
 }  
</script>  
<title>  
</title>  
</head>  
…  

   Далее создадим главную форму для пользовательского ввода, определим скрип-реакцию на нее и при этом передадим ей в качестве параметра action значение vote:

…   
<body>  
<form action="Voter.asp?action=vote" method="post">  
<table border=0 border=0 cellpadding="0" cellspacing="0">  
 <tr>  
 <td colspan=2>  
…  

   Теперь извлечем максимальное значение ключевого поля ID из таблицы вопросов, с тем чтобы получить предел генерации случайных чисел, которым мы будем руководствоваться для выработки псевдослучайного значения:

…  
<%  
  Dim sSQL, Sql, Que, Rs, Rs1, Conn, Dsn, LastID, RndValue, I    
   
  Call Connect()  
  Sql = "SELECT MAX(ID) AS LastID FROM VQuestions"  
  Rs.open Sql, Conn  
  LastID = Rs("LastID")  
  Call Close()  
…  

Затем сгенерируем случайное значение в пределах от 1 до полученного максимального значения:

…  
  RndValue = Int(LastID * Rnd + 1)     
…  

И выберем из таблицы соответствующий вопрос:

…  
  Call Connect()  
  Sql = "select que from VQuestions where id = " & CStr(RndValue)  
  Rs.open Sql, Conn  
  que = rs("que")  
  Call Close()  
   
  Session ("QuestionID") = RndValue  
%>  
…  

  Покажем вопрос пользователю, извлечем (с помощью вышеупомянутой функции) значения его ответов и построим форму для регистрации ответа пользователя. Для этого в цикле будем формировать тег вида  <input type=radio name="poll" value="Ответ">:

…  
 <b><font size="-2" color="black" face="verdana,arial,sans-serif">  
 Примите участие в нашем голосовании, ответьте на вопрос:<br>  
 <%= que %>  
 </font>  
 </b>  
 </tr></td>  
 </table>  
   
<table border=0 border=0 cellpadding="0" cellspacing="0">  
 <tr>  
<%  
  Call FindAns(RndValue)  
   
  I = 1  
   
  Do while not rs.eof  
%>  
  <td>  
  <input type=radio name="poll" value='<%= rs("id") %>'  
  <% If I = 1 Then Response.Write "Checked"%> >  
  <i><font size="-3" color="black" face="verdana,arial,sans-serif">  
  <%=rs("ansdesc") %>  
  </font></i></td>  
<%  
  I = I + 1  
  rs.movenext  
 Loop  
   
 call close()  
%>  
 </tr>  
 <tr><td colspan=2>  
    <input type="hidden" name="quet" value='<%=que%>'>  
    <input type="Submit" name="submit" value="Голосовать" Style="font: 7pt 'Verdana'; Width: 65; Height: 18">&nbsp;  
    <input type="button"  value="Результаты" onclick="gotoResults()" Style="font: 7pt 'Verdana'; Width: 68; Height: 18">  
 </td>  
 </tr>  
   
</table>  
</form>  
</body>  
</html>  

Обработка результатов голосования (файл Voter.asp)

   Для того чтобы результат формировался в той же страничке нашего основного сайта, можно по аналогии с вышеизложенной структурой «облечь» страничку обработки результатов голосования во «включения» файлов подстраничек заголовка вначале и концевика в конце соответственно:

<!-- #include file="mainheader.inc"-->  
   
<%  
 dim dsn,conn,sql,rs  
 dim useraction,ansid,sql1  
 dim ansdesc,newtotal,total,iTotal,t,ImageWidth  
 dim sql_statement  
 dim ors,rs2,ans  
 dim final_total  
 dim ansimage  
 dim votetwice,already,msg,ansPercent  
   
 Sub Connect()  
   dsn = "DSN=Voter; UID=sa;PWD=;database=Voter"  
   Set conn=server.createobject("adodb.connection")  
   Set rs=server.createobject("adodb.recordset")  
   conn.open dsn  
 End Sub  
   
 Sub Close()  
   rs.close  
   set rs = nothing  
   conn.close  
   set conn = nothing  
 End Sub  
…  

  Далее выясним, «каким путем» пользователь попал на данную страничку. Здесь возможны два значения: vote — пользователь проголосовал, и view — пользователь уже голосовал и необходимо показать ему результаты голосования:

…  
 useraction = request("action")  
   
 Select Case useraction  
   
  case "vote"  
    response.write request.form("quet") & "<br><br>"  
…  

   Посредством булевой переменной voteTwice  можно управлять процессом голосования. В частности, установив ее значение в false, можно разрешить пользователям голосовать свободно и независимо от того, голосовал данный пользователь ранее или нет. В противном случае система не будет позволять одному и тому же пользователю голосовать повторно.

   В случае недопустимого повторного голосования переадресуем пользователя на ту же страничку (замкнем страничку на самой себе) с параметром action, равным view, и с дополнительным параметром, свидетельствующим об ошибке msg=1:

…  
    voteTwice = false  
    
    Select Case voteTwice  
      Case true  
        If Request.Cookies("poll_1")="" Then  
                  Response.Cookies("poll_1")="already"  
                  Response.Cookies("poll_1").Expires = Date + 365  
        Else  
                  Response.Redirect "Voter.asp?action=view&msg=1"  
        End If  
    End Select  
…  

  Далее прочитаем ответ пользователя  и обновим общее количество ответов на данный вопрос в соответствии с выбранным пользователем вариантом:

…     
 ansid = Request("poll")  
   
    Call Connect()  
   
    sql = "SELECT * FROM VAnswers WHERE id = " & ansid  
    rs.open sql,conn  
   
    total = rs("total")  
    total = total + 1  
   
    sql1 = "UPDATE VAnswers SET total = " & total & " WHERE id = " & ansid  
    conn.execute(sql1)  
   
    rs.close  
    set rs = nothing  
%>  
…  

Включим подстраничку показа результатов голосования:

…  
 <!--#include file="VShowRes.asp"-->  
   
<%  
case "view"  
…  

  Обработаем параметр msg и в случае ошибки выдадим предупреждение пользователю о недопустимости повторного голосования:

…              
 msg = request("msg")  
 If msg <> "" Then  
   Response.Write "<font size='-2' color='red' face='verdana,arial,sans-serif'>"  
   Response.Write "<br><br><b>Повторное голосование недопустимо!</b></font><br><br>"  
 End If  
   
 Call Connect()  
%>  
   
 <!--#include file="VShowRes.asp"-->  
   
<%  
 conn.close  
 set conn = nothing  
 end select  
%>  
   
<!-- #include file="mainfooter.inc"-->  
   

Как видите, процесс проверки повторного голосования пользователей довольно прост. Для этого используется механизм cookies («ключиков»).

Просмотр результатов голосования (файл VShowRes.asp)

   Нам осталось подготовить страничку, формирующую результаты голосования в графической форме. Для этого сначала вычислим сумму всех количеств данных ответов на один и тот же вопрос (идентификатор вопроса будем читать из сессионной переменной):

…  
<%  
 sql_statement = "SELECT SUM(total) FROM VAnswers WHERE QuestionID = " & Session ("QuestionID")   
 Set oRs = Server.CreateObject("ADODB.recordset")   
 oRs.Open sql_statement,Conn   
   
 final_total = oRs(0).value   
 ors.close  
 set ors = nothing  
…  

   А теперь выберем все варианты ответов на данный вопрос и покажем их пользователю, предварительно задав ширину картинок со столбиками соответствующих ответов и сформировав процентное отношение ответов к их общему числу для каждого их варианта:

…  
 sql = "SELECT * FROM VAnswers WHERE QuestionID = " & Session ("QuestionID") & " ORDER BY id"  
 set Rs2 = conn.execute(sql)  
   
 Response.Write "<b><font size='-2' color='black' face='verdana,arial,sans-serif'>"  
 Response.Write "Результаты голосования</font></b><br>"  
 Response.Write "<table border=1 cellspacing='0'>"  
 t = 1  
   
 Do While Not rs2.eof  
  ans = rs2("total")  
  If ans = 0 Then  
   ansPercent = "0%"  
  Else  
   ansPercent = formatpercent(ans/final_total)  
  End If  
   
  ansImage = replace(ansPercent,"%","")  
  ansImage = ansImage*2  
  ansdesc = rs2("ansdesc")  
   
  Response.Write "<tr><td>"  
  Response.Write "<i><font size='-3' color='black' face='verdana,arial,sans-serif'>"  
  Response.Write ansdesc & "</font></i></td><td>"  
  Response.Write "<i><font size='-3' color='black' face='verdana,arial,sans-serif'>"  
  Response.Write ansPercent & "</font></i>"  
  Response.Write "</td><td>"  
  Response.Write "<img src = images/voter/char"& t &".gif width="& ansImage &" height=5></tr></td>"  
  rs2.movenext  
  t = t + 1  
 Loop  
   
 Response.Write "</tr></td><tr><td colspan=3>"  
 Response.Write "<b><font size='-2' color='black' face='verdana,arial,sans-serif'>"  
 Response.Write "Всего голосовало: " & final_total & " человек</table>"  
 Response.Write "</font></b>"  
%>   
В начало В начало

Заключение

В заключение необходимо указать ряд упрощений, которые мы допустили. Во-первых, как читатель наверняка заметил, система разработана таким образом, что воспринимает не более пяти вариантов ответов на один и тот же вопрос. Мы не стали подробно останавливаться на механизме «ключиков», который использовался для регистрации уже ответившего пользователя. И еще, мы рассмотрели лишь один (частный) случай голосования по схеме «или» и опустили рассмотрение системы электронного голосования по схеме «и». Все эти и другие вопросы усовершенствования системы электронного голосования мы рассмотрим в одной из последующих публикаций настоящей статьи.

Однако разработанная нами система вполне приемлема для использования, а благодаря модульности ее реализации и описанному в статье подходу к ее внедрению в уже существующие сайты. Ее можно применить в качестве системы электронного голосования на сайте практически любой степени сложности.

 

С автором статьи можно связаться по адресу: rouben@iname.com.

КомпьютерПресс 10'2001